#!/usr/bin/env php
<?php
declare(strict_types=1);

if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    require_once __DIR__ . '/vendor/autoload.php';
} elseif (file_exists(__DIR__ . '/../autoload.php')) {
    /** @noinspection PhpIncludeInspection */
    require_once __DIR__ . '/../autoload.php';
} else {
    /** @noinspection PhpIncludeInspection */
    require_once __DIR__ . '/../../autoload.php';
}

telemetry();

switch ($argv[1] ?? '') {
    case 'init':
        require_once __DIR__ . '/src/Cli/init.php';
        init($argv[2] ?? null);
        break;
    case 'cli':
        cliWarning();
        error('Since Bref 2.0, the "bref cli" command has been moved. Read https://bref.sh/docs/runtimes/console#usage');
    case 'layers':
        cliWarning();
        echo "Bref layer ARNs can be found here: https://runtimes.bref.sh/\n\n";
        echo "If you are using Serverless Framework, you can also run the 'serverless bref:layers' command.\n";
        exit(1);
    case 'local':
        cliWarning();
        error('Since Bref 2.0, the "bref local" command has been moved. Read https://bref.sh/docs/local-development/event-driven-functions\n');
    case 'dashboard':
        cliWarning();
        echo "Check out Bref Cloud: https://bref.sh/cloud\n";
        exit(1);
    case '':
        help();
        break;
    default:
        error('Unknown command');
}

function help()
{
    echo "Bref initialization command\n\n";
    echo "Run 'bref init' to get started!\n";
    exit(0);
}

/**
 * @return never-return
 */
function error(string $message): void
{
    echo "\033[31m⨯ $message\033[0m" . PHP_EOL;
    exit(1);
}

function warning(string $message): void
{
    echo "\033[33m$message\033[0m" . PHP_EOL;
}

function success(string $message): void
{
    echo green($message) . PHP_EOL;
}

function green(string $message): string
{
    return "\033[32m$message\033[0m";
}

function cliWarning(): void
{
    warning("Warning: the 'vendor/bin/bref' CLI has been removed in Bref 2." . PHP_EOL);
}

/**
 * Bref telemetry to estimate the number of users and which commands are most used.
 *
 * The data sent is anonymous, and sent over UDP.
 * Unlike TCP, UDP does not check that the message correctly arrived to the server.
 * It doesn't even establish a connection: the data is sent over the network and the code moves on to the next line.
 * That means that UDP is extremely fast (150 micro-seconds) and will not impact the CLI.
 * It can be disabled by setting the `SLS_TELEMETRY_DISABLED` environment variable to `1`.
 *
 * About UDP: https://en.wikipedia.org/wiki/User_Datagram_Protocol
 */
function telemetry(): void
{
    global $argv;
    // Respect the serverless framework env variable
    if ($_SERVER['SLS_TELEMETRY_DISABLED'] ?? false) {
        return;
    }
    // Support cases where the sockets extension is not installed
    if (! function_exists('socket_create')) {
        return;
    }

    // Read `~/.serverlessrc` if it exists
    $userConfigPath = $_SERVER['HOME'] . '/.serverlessrc';
    if (file_exists($userConfigPath)) {
        $userConfig = json_decode(file_get_contents($userConfigPath), true, 512, JSON_THROW_ON_ERROR);
    } else {
        $userConfig = [];
    }

    // Check if we are running in CI
    $ciVars = ['CI', 'CONTINUOUS_INTEGRATION', 'BUILD_NUMBER', 'CI_APP_ID', 'CI_NAME', 'RUN_ID', 'BUILD_ID'];
    $ci = array_reduce($ciVars, function ($carry, $item) {
        return $carry || (isset($_SERVER[$item]) && $_SERVER[$item]);
    }, false);

    $message = json_encode([
        'cli' => 'vendor/bin/bref',
        'v' => 2, // Bref version
        'c' => $argv[1] ?? '',
        'ci' => $ci,
        // anonymous user ID created by the Serverless Framework
        'uid' => $userConfig['frameworkId'] ?? '',
    ], JSON_THROW_ON_ERROR);

    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
    // This IP address is the Bref server.
    // If this server is down or unreachable, there should be no difference in overhead
    // or execution time.
    socket_sendto($sock, $message, strlen($message), 0, '108.128.197.71', 8888);
    socket_close($sock);
}
